package com.linkoog.devtools.intellij.ui.button;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComponentWithBrowseButton;
import com.intellij.openapi.ui.TextComponentAccessor;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.Strings;
import com.intellij.ui.TextAccessor;
import com.intellij.ui.components.JBTextField;
import com.intellij.ui.components.fields.ExtendableTextField;
import com.intellij.util.ui.SwingUndoUtil;
import com.linkoog.devtools.intellij.ui.file_browse.BrowseFolderRunnable;
import com.linkoog.devtools.intellij.ui.file_browse.NoPathCompletion;
import com.linkoog.devtools.intellij.ui.file_browse.TextBrowseFolderListener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.event.DocumentListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 *  带文件选择按钮的文本框
 */
public class TextFieldWithBrowseButton extends ComponentWithBrowseButton<JTextField> implements TextAccessor {
    public TextFieldWithBrowseButton() {
        this((ActionListener)null);
    }

    public TextFieldWithBrowseButton(JTextField field) {
        this(field, null);
    }

    public TextFieldWithBrowseButton(JTextField field, @Nullable ActionListener browseActionListener) {
        this(field, browseActionListener, null);
    }

    public TextFieldWithBrowseButton(JTextField field, @Nullable ActionListener browseActionListener, @Nullable Disposable parent) {
        super(field, browseActionListener);
        if (!(field instanceof JBTextField)) {
            SwingUndoUtil.addUndoRedoActions(field);
        }
        installPathCompletion(FileChooserDescriptorFactory.createSingleLocalFileDescriptor(), parent);
    }

    public TextFieldWithBrowseButton(ActionListener browseActionListener) {
        this(browseActionListener, null);
    }

    public TextFieldWithBrowseButton(ActionListener browseActionListener, Disposable parent) {
        this(new ExtendableTextField(10 /*to prevent infinite resize in grid-box layouts*/), browseActionListener, parent);
    }

    public void addBrowseFolderListener(@Nullable @NlsContexts.DialogTitle String title,
                                        @Nullable @NlsContexts.Label String description,
                                        @Nullable Project project,
                                        FileChooserDescriptor fileChooserDescriptor) {
        fileChooserDescriptor.setTitle(title);
        fileChooserDescriptor.setDescription(description);

        addActionListener(new BrowseFolderActionListener<>(title, description, this, project, fileChooserDescriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT));
        installPathCompletion(fileChooserDescriptor);
    }

    public void addBrowseFolderListener(@NotNull TextBrowseFolderListener listener) {
        listener.setOwnerComponent(this);
        addActionListener(listener);
        installPathCompletion(listener.getFileChooserDescriptor());
    }

    public void addDocumentListener(@NotNull DocumentListener listener) {
        getTextField().getDocument().addDocumentListener(listener);
    }

    protected void installPathCompletion(FileChooserDescriptor fileChooserDescriptor) {
        installPathCompletion(fileChooserDescriptor, null);
    }

    protected void installPathCompletion(FileChooserDescriptor fileChooserDescriptor, @Nullable Disposable parent) {
        Application application = ApplicationManager.getApplication();
        if (application == null || application.isUnitTestMode() || application.isHeadlessEnvironment()) return;
        FileChooserFactory instance = FileChooserFactory.getInstance();
        if (instance != null) {
            instance.installFileCompletion(getChildComponent(), fileChooserDescriptor, true, parent);
        }
    }

    public @NotNull JTextField getTextField() {
        return getChildComponent();
    }

    @Override
    public @NotNull String getText() {
        var text = Strings.notNullize(getTextField().getText());
        if (!(this instanceof NoPathCompletion)) {
            text = FileUtil.expandUserHome(text);
        }
        return text;
    }

    @Override
    public void setText(@NlsSafe @Nullable String text) {
        getTextField().setText(text);
    }

    public boolean isEditable() {
        return getTextField().isEditable();
    }

    @SuppressWarnings("removal")
    public void setEditable(boolean b) {
        getTextField().setEditable(b);
        getButton().setFocusable(!b);
    }




    public static class BrowseFolderActionListener<T extends JComponent> extends BrowseFolderRunnable<T> implements ActionListener {
        public BrowseFolderActionListener(
                @Nullable ComponentWithBrowseButton<T> textField,
                @Nullable Project project,
                FileChooserDescriptor fileChooserDescriptor,
                TextComponentAccessor<? super T> accessor) {
            super(project, fileChooserDescriptor, textField != null ? textField.getChildComponent() : null, accessor);
        }

        public BrowseFolderActionListener(@Nullable @NlsContexts.DialogTitle String title,
                                          @Nullable @NlsContexts.Label String description,
                                          @Nullable ComponentWithBrowseButton<T> textField,
                                          @Nullable Project project,
                                          FileChooserDescriptor fileChooserDescriptor,
                                          TextComponentAccessor<? super T> accessor) {
            super(title, description, project, fileChooserDescriptor, textField != null ? textField.getChildComponent() : null, accessor);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            run();
        }
    }

}
